package org.sevaapp.controller;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sevaapp.configuration.ApplicationConfigurationHelper;
import org.sevaapp.domain.Applicant;
import org.sevaapp.domain.Referral;
import org.sevaapp.dto.ReferralDto;
import org.sevaapp.exception.SevaApplicationException;
import org.sevaapp.security.domain.BaseUser;
import org.sevaapp.security.service.UserService;
import org.sevaapp.service.ReferralService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

public abstract class BaseReferralController extends BaseSevaController {

	private static final Log log = LogFactory.getLog(BaseReferralController.class);

	@Autowired
	private ReferralService serviceObj;
	
	@Autowired
	private UserService userServiceObj;
	
	@Autowired
	private org.dozer.DozerBeanMapper mapper;

	@Autowired
	private Validator validator;

	@Autowired
	ApplicationConfigurationHelper configHelper;

	@Autowired
	private Applicant domainObject;

	/**
	 * Validation method. Every controller should implement this method
	 * to manage the data input validation in a standard and consistent way.
	 */
	public abstract boolean validate(Model model,Referral inputData);

	/**
	 * Controller method for displaying the screen the first time
	 */
	@RequestMapping("/displayReferral.do")
	public String displayReferral(Model model,
			@ModelAttribute("referral") Referral inputData) {
		log.debug("displayReferral() method called.");
		log.debug("Domain Object Data:" + inputData.toString());
		
//		// Get security information
//		String loginId = SecurityContextHolder.getContext().getAuthentication().getName();
//		log.debug("loginId:" + loginId);
//
//		// set the logged in user id so we can display it on the JSP
//		model.addAttribute("loggedInUser", loginId);
		
		// Set default date values.
		Date today = new Date();
		// Creation Date
		inputData.setCreationDate(today);
		// Sign Date
		inputData.setSignDate(today);
		// Evaluation Date
		inputData.setEvaluationDate(today);

		// Set application status to new
		inputData.setApplicationStatus("NEW");
		inputData.setNewReferral(true);

//		Applicant appl = domainObject.findByLoginId(loginId);
//		
//		if ( appl != null ){
//			inputData.setApplicant(appl);
//		}

		// set the welcome message.
		String propertyCode = "seva.app.message";
		String sevaMsg = configHelper.getProperty(propertyCode);
		model.addAttribute("sevaMsg", sevaMsg);

//		try {
//			BaseUser user = userServiceObj.getUser(loginId);
//			log.debug("user:" + user);
//		} catch (SevaApplicationException sae) {
//			log.error("SevaApplicationException occurred when retrieving the user details.", sae);
//		}

		return "referral";
	}

	@RequestMapping("/addReferral.do")
	public String addNewReferral(Model model,@ModelAttribute("referral") ReferralDto inputData,
			BindingResult result) throws SevaApplicationException {
		log.debug("addNewReferral() method called.");
		
//		// Get security information
//		String loginId = SecurityContextHolder.getContext().getAuthentication().getName();
//		log.debug("loginId:" + loginId);
//
//		// set the logged in user id so we can display it on the JSP
//		model.addAttribute("loggedInUser", loginId);
		
		//validate data
		validator.validate(inputData, result);
		boolean validationErrors = result.hasErrors();
		log.debug("validationErrors: " + validationErrors);
		
		if (validationErrors) {
			// Log error information
			int errCount = result.getErrorCount();
			log.debug("errCount: " + errCount);
			
			List errorList = result.getAllErrors();
			Iterator itErr = errorList.iterator();
			while (itErr.hasNext()) {
				FieldError fieldError = (FieldError)itErr.next();
				log.debug("fieldError: " + fieldError);
				
				String errMessage = fieldError.getDefaultMessage();
				log.debug("errMessage: " + errMessage);
			}
			
			model.addAttribute("referralMessage","Could not submit application. Please fill in the required information.");
			return "referral";
			
		}

		// Convert DTO to Domain Objects
		Referral referralData = mapper.map(inputData, Referral.class);
		
		// Call validate method
		boolean isValidData = validate(model,referralData);
		log.debug("isValidData=" + isValidData);
		if (isValidData) {
			if (referralData.getId() == null) {
				// New record, call add method
				// change application status to pending on submit
				referralData.setApplicationStatus("PENDING");
				if (referralData.getExistingReferralId() <= 0)
					referralData.setExistingReferralId(0);
				
//				referralData.getApplicant().setLoginId(loginId);
				referralData.getApplicant().setLoginId("anonymous");
				
				serviceObj.addNewReferral(referralData);
			} else {
				// Existing record, call edit method
				serviceObj.updateReferral(referralData);
			}
			
			mapper.map(referralData,inputData);
			
			model.addAttribute("referralMessage", "Your application has been added/updated successfully");
//			return "referral";
			return "referralSubmit";
		}
	
		return "referral";
	}

	@RequestMapping("/editReferral.do")
	public String editReferral(@ModelAttribute("referral") Referral inputData) {
		log.debug("editReferral() method called.");
		return "referral";
	}

	@RequestMapping("/loadReferral.do")
	public String loadReferral(@ModelAttribute("referral") Referral inputData) {
		log.debug("displayReferral() method called.");
		return "referral";
	}
}
